/*
 * Copyright © 2019-2020  Whale Cloud, Inc. All Rights Reserved.
 *
 * Notice: Whale Cloud Inc copyrights this specification.
 * No part of this specification may be reproduced in any form or means,
 * without the prior written consent of Whale Cloud Inc.
 *
 */
package com.wteam.modules.system.service.impl;

import com.google.common.collect.Sets;
import com.wteam.modules.security.service.JwtUserDetailsService;
import com.wteam.modules.security.service.OnlineUserService;
import com.wteam.modules.system.config.LoginType;
import com.wteam.modules.system.domain.DevelopPlan;
import com.wteam.modules.system.domain.Role;
import com.wteam.modules.system.domain.User;
import com.wteam.modules.system.domain.dto.CusPage;
import com.wteam.modules.system.domain.dto.StudentSubmitDTO;
import com.wteam.modules.system.domain.mapper.UserMapper;
import com.wteam.modules.system.repository.DevelopPlanRepository;
import com.wteam.modules.system.repository.UserRepository;
import com.wteam.modules.system.service.StudentService;
import com.wteam.modules.system.domain.Student;
import com.wteam.modules.system.domain.dto.StudentDTO;
import com.wteam.modules.system.domain.criteria.StudentQueryCriteria;
import com.wteam.modules.system.domain.mapper.StudentMapper;
import com.wteam.modules.system.repository.StudentRepository;
import com.wteam.modules.system.service.UserService;
import com.wteam.modules.system.util.CollectionUtil;
import com.wteam.utils.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cache.annotation.*;
import lombok.RequiredArgsConstructor;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 学生 业务实现层.
 *
 * @author herry_wong
 * @since 2020-12-28
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "student")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class StudentServiceImpl implements StudentService {

    private final UserRepository userRepository;
    private final UserMapper userMapper;

    private final StudentRepository studentRepository;

    private final StudentMapper studentMapper;

    private final RedisUtils redisUtils;

    private final PasswordEncoder passwordEncoder;

    private final OnlineUserService onlineUserService;

    private final UserService userService;



    @Override
    public Map<String,Object> queryAll(StudentQueryCriteria criteria, Pageable pageable){
        Page<Student> page = studentRepository.findAll((root, criteriaQuery, criteriaBuilder) ->  QueryHelper.andPredicate(root, criteria, criteriaBuilder), pageable);
        Page<StudentDTO> studentDTOPage = page.map(studentMapper::toDto);
        Page<StudentDTO> cusPage = new CusPage(studentDTOPage);
        for (StudentDTO studentDTO: cusPage){
            Collections.replaceAll(cusPage.getContent(), studentDTO,findDTOById(studentDTO.getUid()));
        }
        return PageUtil.toPage(cusPage);
    }

    @Override
    public List<StudentDTO> queryAll(StudentQueryCriteria criteria){
        return studentMapper.toDto(studentRepository.findAll((root, criteriaQuery, criteriaBuilder) ->  QueryHelper.andPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
//    @Cacheable(key = "'id:' + #p0")
    public StudentDTO findDTOById(Long uid) {
        Student student = studentRepository.findById(uid).orElse(null);
        ValidUtil.notNull(student, Student.ENTITY_NAME, "uid", uid);
        StudentDTO studentDTO = studentMapper.toDto(student);
        studentDTO.setUserDTO(userMapper.toDto(userRepository.findById(uid).orElse(null)));
        return studentDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentDTO create(StudentSubmitDTO resources) {
        Student student = new Student();
        resources.getUser().setLoginType(LoginType.LOGIN_SYSTEM);
        resources.getUser().setEnabled(true);
        resources.getUser().setRoles(Sets.newHashSet(new Role(2L)));
        resources.getUser().setPassword(passwordEncoder.encode("123456"));
        User user = userRepository.save(resources.getUser());


        student.setUid(user.getId());
        student.setCredit(0.0);
        student.setGrade(1);
        student = studentRepository.save(student);
        StudentDTO studentDTO = studentMapper.toDto(student);
        studentDTO.setUserDTO(userMapper.toDto(user));
        return studentDTO;
    }

    @Override
//    @CacheEvict(key = "'id:' + #p0.id")
    @Transactional(rollbackFor = Exception.class)
    public void update(StudentSubmitDTO resources) {
        Student student = studentRepository.findById(resources.getStudent().getUid()).orElse(null);
        User user = userRepository.findById(resources.getUser().getId()).orElse(null);
        ValidUtil.notNull(student, Student.ENTITY_NAME, "id",resources.getStudent().getUid());

        student.copy(resources.getStudent());
        user.copy(resources.getUser());
        if (resources.getUser().getPassword() != null&&!resources.getUser().getPassword().equals("")){
            user.setPassword(passwordEncoder.encode(resources.getUser().getPassword()));
            redisUtils.del("user::loadUserByUsername:"+user.getUsername());
            JwtUserDetailsService.removeUser(user.getUsername());
            onlineUserService.checkLoginOnUser(user.getUsername(),null);
        }
        userRepository.save(user);
        studentRepository.save(student);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Set<Long> ids) {
        redisUtils.delByKeys("student::id:", ids);
        studentRepository.logicDeleteInBatchById(ids);
        for (Long id: ids){
            userService.deleteOne(id);
        }
    }

    @Override
    public void download(List<StudentDTO> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (StudentDTO student : queryAll) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("学分", student.getCredit());
            map.put("年级", student.getGrade());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void downloadTemplates(HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("学生姓名", null);
    }
}